<?php

namespace app\admin\service;

use app\admin\dao\RoleDao;
use app\admin\model\UM as UM;
use app\common\model\Access;
use app\common\model\Role;
use app\common\model\User;
use ShidianUtil\Exception\DataNotExistException;
use think\exception\ValidateException;

/**
 * Class RoleService
 * @package app\admin\service
 */
class RoleService
{
    // dao
    private RoleDao $roleDao;

    public function __construct(RoleDao $roleDao)
    {
        $this->roleDao = $roleDao;
    }

    /**
     * 列表
     * @param UM|null $user
     * @param int|null $page
     * @param int|null $page_size
     * @return array
     */
    public function index(?UM $user, ?int $page = null, ?int $page_size = null): array
    {
        //这里如果要修改查询，建议把查询放到dao层去
        return $this->roleDao->listRoles($page, $page_size);
    }

    /**
     * 查询
     * @param UM|null $user
     * @param int $id
     * @return Role
     */
    public function read(?UM $user, int $id): ?Role
    {
        $record = Role::where('id', $id)
            ->with([
                'accesses',
            ])
            ->hidden(['accesses'])
            ->find();

        if ($record) {
            // 查询权限

            $accessIds = $record->accesses->column('id');

            $pages = Access::where('level', 0)
                ->with([
                    'sub' => fn($query) => $query->order('ord', 'ASC'),
                ])->order('ord', 'ASC')
                ->select()
                ->each(function (Access $access) use ($accessIds) {

                    $access->sub->each(function (Access $access) use ($accessIds) {

                        $access->isSel = in_array($access->id, $accessIds) ? '1' : '0';
                    });
                });

            $record->setRelation('pages', $pages);
        }

        return $record;
    }

    /**
     * 新增
     * @param UM $user
     * @param array $params
     * @return  void
     */
    public function add(UM $user, array $params): void
    {
        $params['roleType'] = Role::ROLE_TYPE_ADMIN;

        if (is_blank($params['name'] ?? null)) {
            throw new ValidateException('请输入角色名称');
        }

        $this->checkRepeat($params['name']);

        $record = $this->roleDao->insertActive($params, []);

        $this->saveAccess($record, $params['pages'] ?? []);
    }

    /**
     * 更新
     * @param UM $user
     * @param int $id
     * @param array $params
     * @return void
     */
    public function modify(UM $user, int $id, array $params): void
    {
        if (is_blank($params['name'] ?? null)) {
            throw new ValidateException('清输入角色名称');
        }

        $this->checkRepeat($params['name'], $id);

        //这里如果要修改查询，建议把查询就放到这里
        $record = Role::field(true)->where('id', $id)->find();

        if (is_null($record)) {
            throw new DataNotExistException('该角色不存在或已被删除');
        }

        if($record->roleType == Role::ROLE_TYPE_COMPANY){
            throw new ValidateException('该角色不能修改');
        }

        $allowField = [];
        $this->roleDao->updateActive($record, $params, $allowField);

        $this->saveAccess($record, $params['pages'] ?? []);

        // 修改角色后，把该角色下的管理员退出登录，让他们重新登录，获取新权限
        User::where('roleId', $record->id)
            ->update(['token' => '']);
    }


    /**
     * 删除
     * @param UM $user
     * @param int $id
     */
    public function rm(UM $user, int $id): void
    {
        //这里如果要修改查询，建议把查询就放到这里
        $record = Role::field(true)->where('id', $id)->find();

        if (is_null($record)) {
            return;
        }

        if($record->roleType == Role::ROLE_TYPE_COMPANY){
            throw new ValidateException('该角色不能删除');
        }

        $this->roleDao->deleteModel($record);

        // 移除角色的权限
        $record->accesses()->sync([]);

        // 移除用户上的角色
        User::where('roleId', $id)->update(['roleId' => 0]);
    }

    private function checkRepeat($name, $id = null): void
    {
        $record = Role::where('name', $name)
            ->when(is_id($id), fn($query) => $query->where('id', '<>', $id))
            ->find();

        if ($record) {
            throw new ValidateException('该角色名称已存在');
        }
    }

    private function saveAccess(Role $role, $pages)
    {
        if (empty($pages)) {
            return;
        }

        $ids = [];
        foreach ($pages as $page0) {
            foreach ($page0['sub'] as $page1) {
                $isSel = $page1['isSel'] ?? '0';
                if ($isSel == '1') {
                    $ids[] = $page1['id'];
                }
            }
        }

        $role->accesses()->sync($ids);
    }

}
